var engine = function(init_world) {

	/* create pixi application
	 * there's a chance the initial width/height is useless
	 * */
	this.container = document.getElementById("game");

	/* save game dimensions */
	this.width = this.container.clientWidth;
	this.height = this.container.clientHeight;

	this.app = new PIXI.Application({width: this.width, height: this.height});
	this.container.appendChild(this.app.view);

	this.input = function(e) {
		if (this.world) {
			this.world.input(e.x, e.y);
		}
	};

	/* capture input
	 */
	this.app.view.onpointerdown = this.input.bind(this);

	/* resizing
	 * listen for resizing even,
	 * then resize the pixi renderer
	 * and update the current word to resize itself
	 */
	this.resize = function() {

		// Get the parent
		const parent = this.app.view.parentNode;
	
		this.width = parent.clientWidth;
		this.height = parent.clientHeight;
	
		// Resize the renderer
		this.app.renderer.resize(this.width, this.height);
	
		// Resize world
		if (this.world) {
			this.world.resize();
		}
	}
	window.addEventListener('resize', this.resize.bind(this));

	/* mute */
	this.muted = false;

	/* set a new world
	 */
	this.setWorld = function(new_world) {
		this.nextWorld = new_world;
	}

	// called by the engine when a world has finished loading
	var worldLoaded = function() {
		this.world = this.loadingWorld;
		this.world.start();
		this.world.resize();
		delete this.loadingWorld;
	}

	/* the engine calls this to start loading of a new world
	 * should not be called manually
	 */
	this.loadWorld = function(world) {

		// if previous world is still active, remove it
		if (this.previousWorld) {
			this.previousWorld.destroy();
			delete this.previousWorld;
		}

		// if there is currently a world, mark it as previous
		if (this.world) {
			this.previousWorld = this.world;
			delete this.world;
		}

		// start loading the new world
		this.loadingWorld = new world();
		this.app.stage.addChild(this.loadingWorld.container);

		// notify the engine that the world has started loading
		delete this.nextWorld;

		// load assets
		var assets = this.loadingWorld.assets();
		if (assets) {
			PIXI.loader.add(assets);
		}
		PIXI.loader.load( worldLoaded.bind(this) );

	}

	/* responsible for updating the engine and the current world
	 */
	this.update = function() {

		// update current world
		if (this.world) {
			this.world.update();
		}

		// if available, load next world
		if (this.nextWorld) {
			this.loadWorld(this.nextWorld);
		}

	} // update

	// start update periodically
	this.app.ticker.add(this.update.bind(this));

} // engine
